/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						 hue_pixel.cpp

	$Header: /heroes4/hue_pixel.cpp $

	$NoKeywords: $

 ************************************************************************/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )


#include "hue_pixel.h"

#include <assert.h>
#include <math.h>
#include "convert_16_bit.h"

// ----------------------------------------------------------------
// pixel encoded as hue, saturation, brightness
// ----------------------------------------------------------------
void t_hue_pixel::adjust_brightness( int delta )
{
	if ( delta < 256 )
		m_brightness = (m_brightness * delta) >> 8;
	else if (delta > 256)
	{
		m_brightness = 255 - (( 255 - m_brightness ) << 8) / delta;
	}
}


// ----------------------------------------------------------------
// pixel encoded as hue, saturation, brightness
// ----------------------------------------------------------------
void t_hue_pixel::adjust_hue( int target, int delta )
{
	if (delta == 0)
		return;

	int difference = target - m_hue;

	if (abs( difference ) > k_max_hue / 2)
	{
		difference = m_hue - target;
		m_hue -= (delta * difference) >> 8;
	}
	else
	{
		m_hue += (delta * difference ) >> 8;
	}
	if (m_hue < 0)
		m_hue += k_max_hue;
	if (m_hue > k_max_hue)
		m_hue -= k_max_hue;
}

// ----------------------------------------------------------------
// pixel encoded as hue, saturation, brightness
// ----------------------------------------------------------------
void t_hue_pixel::adjust_saturation( int delta )
{
	if ( delta < 256 )
		m_saturation = (m_saturation * delta) >> 8;
	else if (delta > 256)
		m_saturation = 255 - (( 255 - m_saturation ) << 8) / delta;
}

// ----------------------------------------------------------------
// pixel encoded as hue, saturation, brightness
// ----------------------------------------------------------------
t_uint16 t_hue_pixel::get_color() const
{
	int		 brightness = m_brightness;
	int		 saturation = m_saturation;
	int	     red;
	int      green;
	int      blue;

	if (saturation == 0)
		return convert_to_16_bit( brightness, brightness, brightness );

	int hue		  = m_hue;
	int range	  = brightness * saturation / 255;
	int min_value = brightness - range;

	switch (hue >> 7)
	{
		case 0:
			red   = brightness;
			blue  = min_value;
			green = blue + ((hue * range) >> 7);
			break;

		case 1:
			green = brightness;
			blue  = min_value;
			red   = blue - (((hue - k_green) * range) >> 7);
			break;

		case 2:
			green = brightness;
			red   = min_value;
			blue  = red + (((hue - k_green) * range) >> 7);
			break;

		case 3:
			blue  = brightness;
			red   = min_value;
			green = red - (((hue - k_blue) * range) >> 7);
			break;

		case 4:
			blue  = brightness;
			green = min_value;
			red   = green + (((hue - k_blue) * range) >> 7);
			break;

		case 5:
			red   = brightness;
			green = min_value;
			blue  = green - (((hue - k_max_hue) * range) >> 7);
			break;
	}
	return convert_to_16_bit( red, green, blue );
}

// ----------------------------------------------------------------
// pixel encoded as hue, saturation, brightness
// ----------------------------------------------------------------
t_pixel_24 t_hue_pixel::get_pixel_24() const
{
	int		 brightness = m_brightness;
	int		 saturation = m_saturation;
	int	     red;
	int      green;
	int      blue;

	if (saturation == 0)
		return convert_to_24_bit(convert_to_16_bit( brightness, brightness, brightness ));

	int hue		  = m_hue;
	int range	  = brightness * saturation / 255;
	int min_value = brightness - range;

	switch (hue >> 7)
	{
		case 0:
			red   = brightness;
			blue  = min_value;
			green = blue + ((hue * range) >> 7);
			break;

		case 1:
			green = brightness;
			blue  = min_value;
			red   = blue - (((hue - k_green) * range) >> 7);
			break;

		case 2:
			green = brightness;
			red   = min_value;
			blue  = red + (((hue - k_green) * range) >> 7);
			break;

		case 3:
			blue  = brightness;
			red   = min_value;
			green = red - (((hue - k_blue) * range) >> 7);
			break;

		case 4:
			blue  = brightness;
			green = min_value;
			red   = green + (((hue - k_blue) * range) >> 7);
			break;

		case 5:
			red   = brightness;
			green = min_value;
			blue  = green - (((hue - k_max_hue) * range) >> 7);
			break;
	}
	return t_pixel_24( red, green, blue );
}


// ----------------------------------------------------------------
// pixel encoded as hue, saturation, brightness
// ----------------------------------------------------------------
void t_hue_pixel::set_color( int red, int green, int blue )
{
	int max_value = red;
	int min_value = red;

	if (red < green)
		max_value = green;
	else
		min_value = green;
	if (max_value < blue)
		max_value = blue;
	if (min_value > blue)
		min_value = blue;

	int range     = max_value - min_value;

	m_brightness = max_value;
	if (max_value == 0)
		m_saturation = 0;
	else
		m_saturation = 255 * range / max_value;
	if (range == 0)
		m_hue = 0;
	else
	{
		if (blue == max_value)
		{
			m_hue = k_blue + (( red - green ) << 7)/ range;
			if (m_hue == k_max_hue)
				m_hue = 0;
		}
		else if (green == max_value)
			m_hue = k_green + (( blue - red ) << 7) / range;
		else
		{
			m_hue = (( green - blue ) << 7) / range;
			if (m_hue < 0)
				m_hue += k_max_hue;
		}
	}
}



